// reverting git to the last commit
// git reset --hard HEAD

#include <QStringList>
#include <iostream>
#include <assert.h>

#include "include/treeitem.h"
#include "include/Common.h"
#include "include/knowledgebase.h"
#include "include/itreeitemfactory.h"

using namespace std;

//QMap<QUuid, TreeItem*> TreeItem::parentPointerFinder = QMap<QUuid, TreeItem*>();




//TreeItem::TreeItem(const QVector<QVariant> &data, TreeItem *parent)
//	: uuid(QUuid::createUuid())
//	//, itemData(data)
//	, parentItem(parent)
//	, card(new Card)
//	, iscard(false)
//	, ispaused(false)
//	, m_pKnowledgeBase(parent != 0 ? parent->knowledgeBase() : 0)
//{
//	//The commented code has been moved to ITreeItemFactory to make constructor reenterable
//	//if (Settings::m_requestLeaf)
//	//setIsCard(true);
//}


TreeItem::TreeItem(TreeItem * parent)
	: uuid(QUuid::createUuid())
	//, itemData(2)
	, parentItem(parent)
	, card(new Card)
	, iscard(false)
	, ispaused(false)
	, m_pKnowledgeBase(parent != 0 ? parent->knowledgeBase() : 0)
{
	//The commented code has been moved to ITreeItemFactory to make constructor reenterable
	//if (Settings::m_requestLeaf)
	//setIsCard(true);
}


Deck* TreeItem::getDeck() const
{
	return m_pKnowledgeBase != 0 ? m_pKnowledgeBase->deck() : 0;
}


KnowledgeBase* TreeItem::knowledgeBase() const
{
	if (m_pKnowledgeBase != 0)
		return m_pKnowledgeBase;

	if (parent() != 0)
		return parent()->knowledgeBase();

	return 0;
}


void TreeItem::setKnowledgeBase(KnowledgeBase* value)
{
	m_pKnowledgeBase = value;
}


TreeItem::~TreeItem()
{
	qDeleteAll(childItems);
}


TreeItem *TreeItem::child(int number)
{
	return childItems.value(number);
}


int TreeItem::childCount() const
{
	return childItems.count();
}


unsigned int TreeItem::getNumCards() const
{
	unsigned int count = 0;

	for (QList<TreeItem*>::const_iterator it = childItems.begin(); it != childItems.end(); it++)
	{
		if ((*it)->iscard && !(*it)->isPaused())
			count++;
		count += (*it)->getNumCards();
	}
	return count;
}


bool TreeItem::hasChildren() const //this method is to check whether the children collection isempty,
{	//methods returning count are not suggested by some authors for this purpose
	return !childItems.empty();
}


int TreeItem::childNumber() const
{
	if (parentItem)
		return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));

	return 0;
}


int TreeItem::columnCount() const
{
	return 2;
	//return itemData.count();
}


QVariant TreeItem::data(int column) const
{
	switch ((DataColumn)column)
	{
	case QuestionColumn:
		return questionText();
	case AnswerColumn:
		return answerText();
	default:
		return QVariant();
	}
}


bool TreeItem::insertChildren(int position, int count, ITreeItemFactory* factory)
{
	if (position < 0 || position > childItems.size())
		return false;

	for (int row = 0; row < count; ++row) {
		//QVector<QVariant> data(columns);

		TreeItem *item =  factory != 0 ? factory->createTreeItem(this) : new TreeItem(this);
		childItems.insert(position, item);
		knowledgeBase()->setTreeItem(item->getUuid(), item);
	}

	return true;
}


TreeItem *TreeItem::parent()
{
	return parentItem;
}


const TreeItem *TreeItem::parent() const
{
	return parentItem;
}


bool TreeItem::removeChildren(int position, int count)
{
	if (position < 0 || position + count > childItems.size())
		return false;

	for (int row = 0; row < count; ++row)
		delete childItems.takeAt(position);

	return true;
}


bool TreeItem::cutChildren(int position, int count)
{
	if (position < 0 || position + count > childItems.size())
		return false;

	cout << "delete row " << 0 << endl;
	Settings::m_buffer = childItems.takeAt(position);

	return true;
}


bool TreeItem::paste(int position, int/* count*/)
{
	if (position < 0)
		return false;

	if (Settings::m_buffer != 0)
	{
		//cout << "insert row " << 0 << endl;
		Settings::m_buffer->parentItem = this;
		childItems.insert(position, Settings::m_buffer);
	}
	Settings::m_buffer = 0;

	return true;
}


bool TreeItem::setData(int column, const QVariant &value)
{
	return setText( (DataColumn)column, value.toString() );
}


QDataStream &operator<<( QDataStream &stream, const TreeItem &data )
{
	stream << data.uuid;
	stream << data.ispaused;
	bool isCard = data.isCard();
	if (isCard && data.card->getUuid().isNull())
		isCard = false;

	stream << isCard;

	if (isCard)
	{
		stream << data.card->getUuid();
		assert(data.card->getUuid().isNull() == false);
	}

	QVector<QVariant> strData;
	strData << data.questionField() << data.answerField();
	stream << strData;
	QUuid parentItem = (data.parent() != 0 ? data.parent()->uuid : QUuid());
	stream << parentItem;

	stream << data.imgMap;

	stream << data.childItems.count();

	for (QList<TreeItem*>::const_iterator it = data.childItems.begin(); it != data.childItems.end(); it++)
		stream << **it;

	return stream;
}

void TreeItem::readItemData(QDataStream& stream)
{
	QVector<QVariant> itemData;
	stream >> itemData;
	if (itemData.size() > QuestionColumn)
		setQuestionField(itemData[QuestionColumn].isValid() ? itemData[QuestionColumn].toString() : "");
	if (itemData.size() > AnswerColumn)
		setAnswerField(itemData[AnswerColumn].isValid() ? itemData[AnswerColumn].toString() : "");
}


void TreeItem::readVer0(QDataStream &stream)
{
	stream >> uuid;
	stream >> ispaused;
	stream >> iscard;
	QUuid cardid;
	if (iscard)
		stream >> cardid;

	readItemData(stream);

	QUuid parentId;
	stream >> parentId;
	int count;
	stream >> count;

	if (cardid.isNull() == false)
	{
		Card* deckCard = getDeck()->getCard(cardid);
		card = deckCard;
	}

	parentItem = m_pKnowledgeBase->getTreeItem(parentId);

	m_pKnowledgeBase->setTreeItem(uuid, this);

	for (int i = 0; i < count; i++)
	{
		TreeItem* item = new TreeItem(this);
		item->setKnowledgeBase(knowledgeBase());
		item->readVer0(stream);
		childItems.append(item);
	}
}

void TreeItem::readFrom(QDataStream &stream)
{
	stream >> uuid;
	stream >> ispaused;
	stream >> iscard;
	QUuid cardid;
	if (iscard)
		stream >> cardid;

	readItemData(stream);
	QUuid parentId;
	stream >> parentId;   //parentId

	stream >> imgMap; //imgMap

	int count;
	stream >> count;

	if (cardid.isNull() == false)
	{
		Card* deckCard = getDeck()->getCard(cardid);
		card = deckCard;
	}

	parentItem = m_pKnowledgeBase->getTreeItem(parentId);

	m_pKnowledgeBase->setTreeItem(uuid, this);

	for (int i = 0; i < count; i++)
	{
		TreeItem* item = new TreeItem(this);
		item->setKnowledgeBase(knowledgeBase());
		item->readFrom(stream);
		childItems.append(item);
	}
}


bool TreeItem::isInDeck()
{
	return getDeck()->hasCard(card->getUuid());
}


bool TreeItem::isCard() const
{
	return iscard;
}


void TreeItem::setIsCard(bool aB)
{
	if (aB)
	{
		if (card->getUuid().isNull())
			card->initUuid();

		card->setQuestion(questionField());
		card->setAnswer(answerField());
	}
	else
	{
		iscard = aB;
		setData(0, QVariant(card->getQuestion()));
		setData(1, QVariant(card->getAnswer()));
	}

	if (aB && isInDeck() == false)
		getDeck()->addCard(card);
	iscard = aB;
}


bool TreeItem::isDue() const
{
	if (ispaused == false)
	{
		if (isCard())
			return card->isDue();
		for (QList<TreeItem*>::const_iterator it = childItems.begin(); it != childItems.end(); it++)
		{
			if ((*it)->isDue())
				return true;
		}
	}
	return false;
}


int TreeItem::getDueDate() const
{
	if (isCard() && childItems.size() == 0)
	{
		return card->getDueDate();
	}
	else if (isCard() == false && childItems.size() != 0)
	{
		unsigned long long int dueDate = 0;
		int numCards = 0;
		for (QList<TreeItem*>::const_iterator it = childItems.begin(); it != childItems.end(); it++)
		{
			if ((*it)->isCard())
			{
				int e = (*it)->getCard()->getDueDate();
				if (e != 0 && e != -1)
				{
					dueDate += e;
					numCards++;
				}
			}
			else
			{
				int e = (*it)->getDueDate();

				if (e != 0 && e != -1)
				{
					dueDate += e;
					numCards++;
				}
			}
		}
		return numCards != 0 ? dueDate / numCards : 0;
	}
	return 0;
}


void TreeItem::getDueCardsDepthFirst(TreeItem*& pTreeItem, CardInfo& info, QList<QString> lineage) const
{
	if (this->parent() != 0)
		lineage.append(this->parent()->data(0).toString());
	if (pTreeItem != 0)
		return;
	if (ispaused == false)
	{
		if (isCard() && card->isDue())
		{
			info.m_lineage = lineage;
			info.m_card = card;
			pTreeItem = const_cast<TreeItem*>(this);
			return;
		}
		for (QList<TreeItem*>::const_iterator it = childItems.begin(); it != childItems.end(); it++)
			(*it)->getDueCardsDepthFirst(pTreeItem, info, lineage);
	}
}


void TreeItem::invert()
{
//	if (itemData.size() == 1)
//	{
//		itemData.push_back(itemData[0]);
//		itemData[0] = QVariant();
//	}
//	else if (itemData.size() == 2)
//	{
//		QVariant temp;
//		temp = itemData[0];
//		itemData[0] = itemData[1];
//		itemData[1] = temp;
//	}

	QString temp = questionField();
	setQuestionField(answerField());
	setAnswerField(temp);

	if (isCard())
	{
		QString temp = card->getQuestion();
		card->setQuestion(card->getAnswer());
		card->setAnswer(temp);
//		card->reset();
	}

	//swap images
	if (!imgMap.isEmpty())
	{
		ImageMap tmp(imgMap);
		imgMap.clear();
		if (tmp.contains(AnswerColumn))
			imgMap[QuestionColumn] = tmp[AnswerColumn];
		if (tmp.contains(QuestionColumn))
			imgMap[AnswerColumn] = tmp[QuestionColumn];
	}
}


bool TreeItem::hasCards() const
{
	if (isCard())
		return true;
	for (QList<TreeItem*>::const_iterator it = childItems.begin(); it != childItems.end(); it++)
	{
		if ((*it)->hasCards())
			return true;
	}
	return false;
}


void TreeItem::setIsPaused(bool b)
{
	ispaused = b;
}


bool TreeItem::isPaused() const
{
	if (ispaused)
		return true;

	if (parent() != 0)
		return parent()->isPaused();

	return false;
}


void TreeItem::getLineage(QList<QString>& lineage) const
{
	const TreeItem* pParent = parent();
	if (pParent)
	{
		//if (itemData.size() != 0)
			lineage.push_back(questionField());
		pParent->getLineage(lineage);
	}
}


bool TreeItem::hasImage(TreeItem::DataColumn col) const
{
	QMap<int, QImage>::const_iterator it = imgMap.find(col);
	if (it == imgMap.end())
		return false;

	//std::pair<int, QImage> p = *it;
	QImage img = it.value();
	return !img.isNull() && img.width() > 0 && img.height() > 0;
}


QImage TreeItem::image(TreeItem::DataColumn col) const
{
	QMap<int, QImage>::const_iterator it = imgMap.find(col);
	return it != imgMap.end() ? it.value() : QImage();
}


void TreeItem::setImage(TreeItem::DataColumn col, QImage value)
{
	imgMap[col] = value;
}


void TreeItem::resetImage(TreeItem::DataColumn col)
{
	imgMap.remove(col);
}


QString TreeItem::questionText() const
{
	QString v = isCard() ?  card->getQuestion() : questionField();

	//std::cout << "questionText: --" << v.toStdString() << "--" << std::endl;

	return v;
}


void TreeItem::setQuestionText(const QString& value)
{
	if (iscard)
	{
		card->setQuestion(value);
		getDeck()->updateCard(card);
	}
	else
	{
		//assert(itemData.size() > QuestionColumn);
		setQuestionField(value);
		//getDeck()->updateCard(card);
	}
}


QString TreeItem::answerText() const
{
	return isCard() ?  card->getAnswer() : answerField();
}


void TreeItem::setAnswerText(const QString& value)
{
	if (iscard)
	{
		card->setAnswer(value);
		getDeck()->updateCard(card);
	}
	else
	{
		setAnswerField(value);
	}
}


bool TreeItem::setText(DataColumn col, const QString& value)
{
	switch (col)
	{

	case QuestionColumn:
	{
		if (questionText() == value)
			return false;

		setQuestionText(value);
		return true;
	}

	case AnswerColumn:
	{
		if (answerText() == value)
			return false;

		setAnswerText(value);
		return true;
	}

	default:
	{
		return false;
	}

	} //switch
}


QString TreeItem::getText(DataColumn col) const
{
	return data(col).toString();
}


int TreeItem::indexOfChild(TreeItem* childItem) const
{
	return childItems.indexOf(childItem);
}


QString TreeItem::questionField() const
{
	return _question;
}

QString TreeItem::answerField() const
{
	return _answer;
}

void TreeItem::setQuestionField(const QString& value)
{
	_question = value;
}

void TreeItem::setAnswerField(const QString& value)
{
	_answer = value;
}
